package com.rtos.model.memory;

import com.rtos.common.ProcessStatus;
import com.rtos.model.process.PCB;
import com.rtos.model.process.Process;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import lombok.Data;
import lombok.extern.java.Log;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

/**
 * @Author: biubiu0002
 * @Date: 2021-09-03 10:04
 * 内存空间分配表 Memory Space Allocation Table
 * 单例
 **/
@Log
public class MAT {
    private static ObservableList<MATNode> MATList = FXCollections.observableArrayList();

    public static List<MATNode> getMATList(){
        return MATList;
    }

    private static MAT mat;


    private MAT() {
        MATNode node = new MATNode(-1, 0, 511, true, true);
        MATList.add(node);
    }

    public static MAT getInstance() {
        if(mat==null){
            mat = new MAT();
        }
        return mat;
    }

    public int findFirstValidSpace(int size){
//        MATNode head = MATList.get(0);
        for (MATNode next : MATList) {
            if (next.isFree() && next.getSize() > size) {
                return next.getAddress().getValue();
            }
        }
        return -1;
    }

    public synchronized boolean free(Process process) {
        MATNode node = getByPID(process.getPcb().getPID());
        try {
            if (node.isFree()) {
                throw new Exception("内存回收失败，不要对空闲内存进行回收");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }

        MATNode cur = node;
        node.setPID(-1);
        node.setFree(true);
        int index = MATList.indexOf(node);
        MATNode prevNode = null;
        MATNode nextNode = null;
        if (index > 0) {
            prevNode = MATList.get(index - 1);
        }
        if (index + 1 < MATList.size()) {
            nextNode = MATList.get(index + 1);
        }
        //与前一块合并
        if (prevNode != null) {
            boolean prevFree = prevNode.isFree();
            if (prevFree) {
                cur = prevNode;
                cur.setEndAddress(node.getEndAddress());
                cur.setSize((cur.getSize() + node.getSize()));
                MATList.remove(node);
            }
        }
        //与后一块合并
        if (nextNode != null) {
            boolean nextFree = nextNode.isFree();
            if (nextFree) {
                cur.setEndAddress(nextNode.getEndAddress());
                cur.setSize( (cur.getSize() + nextNode.getSize()));
                MATList.remove(nextNode);
            }
        }
        return true;
    }

    private MATNode getByPID(Integer pid) {
        MATNode res = null;
        for (MATNode node : MATList) {
            if (node.getPID()==pid ) {
                res = node;
            }
        }
        return res;
    }


    /**
     * 找到第一块空闲区，把空闲区分成两部分
     *
     * @param process
     * @return
     */
    public synchronized boolean alloc(Process process) {
        //进程起始地址在process中定义
        int processSize = process.getSize();
        int processAddress = mat.findFirstValidSpace(process.getSize());
        if(processAddress==-1){
            log.warning("没有足够空间分配给进程");
            return false;
        }
        int processEndAddress = processSize+processAddress - 1;
        if(processAddress==-1){
            return false;
        }



        //进程起始地址在MemoryDispatcher中给出
        //随机进程内存大小

        MATNode allocNode = new MATNode(process.getPcb().getPID(), processAddress,processEndAddress,
                false, true);
        for (MATNode node : MATList) {
            int index = MATList.indexOf(node);
            if (node.isFree()) {
                int nodeAddress = node.getAddress().getValue();
                int nodeEndAddress = node.getEndAddress().getValue();
                //E-A+1 = size
                //E = size+A-1
                if (processAddress >= nodeAddress && processEndAddress < nodeEndAddress) {
                    MATNode prevNode = new MATNode(-1, nodeAddress, processAddress - 1, true,
                            true);
                    MATNode nextNode = new MATNode( -1,processEndAddress + 1, nodeEndAddress, true,
                            true);
                    MATList.remove(node);
                    if(prevNode.getEndAddress().getValue()>0){
                        if(prevNode.getEndAddress().get()>prevNode.getAddress().getValue())  {
                            MATList.add(index, prevNode);
                            MATList.add(index + 1, allocNode);
                            MATList.add(index + 2, nextNode);

                        }else{
                            MATList.add(index, allocNode);
                            MATList.add(index + 1, nextNode);


                        }
                    }
                    else{
                        MATList.add(index, allocNode);
                        MATList.add(index + 1, nextNode);

                    }
                    MATNode newNode = new MATNode(allocNode.getPID(), allocNode.getAddress().get(), allocNode.getEndAddress().get(),
                            allocNode.isFree(), allocNode.isUSer());
                    process.setMatNode(newNode);

                    return true;

//                    break;
                }
            }
        }
        /**
         * 进程携带matnode信息
         */

        return false;
    }


}



